﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace WorldClock.BO
{
    public class TimeZoneInfoViewModel : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private TimeZoneInfo _timeZoneInfo;
        private string _shortName;
        private bool _adjustmentsInitialized;
        private DateTime _dstStart = new DateTime();
        private DateTime _dstEnd = new DateTime();
        private System.TimeZoneInfo.AdjustmentRule _adjustement = null;

        public string Name 
        {
            get
            {
                return _timeZoneInfo.DisplayName;
            }
        }

        public string ShortName
        {
            get
            {
                return _shortName;
            }
            set
            {
                _shortName = value;
                RaisePropertyChanged("ShortName");
            }
        }

        public string Id 
        {
            get
            {
                return _timeZoneInfo.Id;
            }
        }

        public DateTime Time
        {
            get
            {
                if (!_adjustmentsInitialized)
                {
                    System.TimeZoneInfo.AdjustmentRule[] adjustements = _timeZoneInfo.GetAdjustmentRules();
                    if (adjustements != null && adjustements.Length > 0)
                    {
                        foreach (System.TimeZoneInfo.AdjustmentRule adjust in adjustements)
                            if (DateTime.UtcNow + _timeZoneInfo.BaseUtcOffset > adjust.DateStart &&
                                DateTime.UtcNow + _timeZoneInfo.BaseUtcOffset < adjust.DateEnd)
                            {
                                _adjustement = adjust;
                                break;
                            }
                    }
                }
                if (_adjustement != null)
                {
                    if (!_adjustmentsInitialized)
                    {
                        _dstStart = GetDateTimeFromTransitionTime(_adjustement.DaylightTransitionStart);
                        _dstEnd = GetDateTimeFromTransitionTime(_adjustement.DaylightTransitionEnd);
                        _adjustmentsInitialized = true;
                    }
                    DateTime dt = DateTime.UtcNow + _timeZoneInfo.BaseUtcOffset;
                    if (dt > _dstStart && dt < _dstEnd)
                        return dt + _adjustement.DaylightDelta;
                    else
                        return dt;
                }
                else
                {
                    _adjustmentsInitialized = true;
                    return DateTime.UtcNow + _timeZoneInfo.BaseUtcOffset;
                }
            }
        }

        public double TotalMinutes
        {
            get { return Time.TimeOfDay.TotalMinutes; }
        }

        public int Seconds
        {
            get { return Time.Second; }
        }
        
        public string AM_PM 
        {
            get
            {
                if (Time.Hour >= 0 && Time.Hour < 12)
                    return "AM";
                else
                    return "PM";
            }
        }

        public TimeZoneInfoViewModel(TimeZoneInfo timeZoneInfo)
        {
            _timeZoneInfo = timeZoneInfo;
            _shortName = _timeZoneInfo.StandardName;            
        }

        public DateTime GetDateTimeFromTransitionTime(System.TimeZoneInfo.TransitionTime transitionTime)
        {
            if (!transitionTime.IsFixedDateRule)
            {
                if (transitionTime.Week < 5)
                {
                    int currentWeek = 0;
                    DateTime dt = new DateTime(DateTime.Now.Year, transitionTime.Month, 1);
                    for (int i = 1; i < DateTime.DaysInMonth(dt.Year, dt.Month); i++)
                    {
                        dt = new DateTime(DateTime.Now.Year, transitionTime.Month, i);
                        if (dt.DayOfWeek == DayOfWeek.Sunday)
                            currentWeek++;
                        if (dt.DayOfWeek == transitionTime.DayOfWeek &&
                            currentWeek == transitionTime.Week)
                        {
                            return dt;
                        }
                    }
                }
                else
                {
                    DateTime dt = new DateTime(DateTime.Now.Year, transitionTime.Month, 1);
                    for (int i = DateTime.DaysInMonth(dt.Year, dt.Month); i > 1; i--)
                    {
                        dt = new DateTime(DateTime.Now.Year, transitionTime.Month, i);
                        if (dt.DayOfWeek == transitionTime.DayOfWeek)
                            return dt;
                    }
                }
            }
            else
            {
                DateTime dt = new DateTime(DateTime.Now.Year, transitionTime.Month, transitionTime.Day);
                return dt;
            }
            throw new Exception("Failed to convert a TransitionTime to a DateTime");
        }

        public void RaiseTimeChanged()
        {
            RaisePropertyChanged("TotalMinutes");
            RaisePropertyChanged("Seconds");
            RaisePropertyChanged("AM_PM");
        }

        public void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }        
    }
}
